/*
  (C) 2005 Adam D. Bradley

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package step;

import snbenchlib.Log;
import snbenchlib.Trace;
import snobject.snBoolean;
import snobject.snObject;


public class LevelTriggerNode extends AbstractTrigger
{
	public LevelTriggerNode(String id)  { super(id); }

	public LevelTriggerNode() { super(); }

	protected void SetWanted(boolean v) {
		/*
		 * Persistent triggers are always "wanted",
		 * if they are "root" nodes.  Otherwise
		 * they inheriet demand from above
		 */ 
		
		if(!this.IsOrphan()){
			rt_wanted = v;
		}
		else{
			rt_wanted = true;
		}
		
		/* 
		 * Do not recurse as children are 
		 * "under our control" -- their
		 * wanted states are controlled
		 * by the evaluator
		 */
	}
	public boolean IsEnabled() {
		switch(state) {
		case ASLEEP:
			return true;
			// MJO:2/14 
			// return wanted;
		case TESTING:
			return HasFreshInput(0);
		case PROCESSING:
			return HasFreshInput(1);
		}
		assert(false);
		return false;
	}

	public void Evaluate() throws EvaluationFailure {
		int oldstate = state;
		
		switch(state) {
		case ASLEEP:
			children[0].ClearEvaluatedFlags();
			children[1].ClearEvaluatedFlags();
			children[1].SetWanted(false);
			children[0].SetWanted(true);
			ClearFreshInputs();
			state = TESTING;
			break;
			
		case TESTING:
			snObject pred = GetInput(0);
			assert(pred != null);
			if (pred.equals(snBoolean.TRUE)) {
				children[0].SetWanted(false);
				children[1].SetWanted(true);
				state = PROCESSING;
			} else {
				state = ASLEEP;
			}
			break;
			
		case PROCESSING:
			SetValue(GetInput(1));
			ClearFreshInputs();
			PushResult();
			state = ASLEEP;
			break;
			
		default:
			assert(false);
		}
		
		Log.evaluator.log(
				"Trigger "+ super.ID + " state advancement from " + StateName(oldstate) + " to " + StateName(state),
				Trace.VERBOSE);
	}
	
	@Override
	public Node ShallowCopy() {
		LevelTriggerNode cn = new LevelTriggerNode(this.ID);
		Node.CopyNonRTPropertiesFromAtoB(this,cn);
		return cn;
	}

	// Serializer
	public String TagName() { return "level_trigger"; }
}
